package fr.gmdev.mail.util;

import java.util.*;
import java.io.*; //import com.experian.pid.edi.ConstantsEDI;
//import com.experian.pid.filemgt.*;
import java.util.zip.*;
import java.nio.channels.*;

public class StreamUtility {
	/**
	 * 
	 * @param taillePrevisionnelle
	 * @return
	 */
	public static ByteArrayOutputStream getOutputStream(int taillePrevisionnelle) {
		return new ByteArrayOutputStream(Math.max(taillePrevisionnelle,
				1024*32));
	}

	public static byte[] fileToByte(File fic) throws IOException {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(fic);
			return inputStreamToByte(fis, fis.available());
		} finally {
			close(fis);
		}

	}

	public static byte[] fileToGzByte(File fic) throws IOException {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(fic);
			return inputStreamToGZipByte(fis, (fis.available() / 2) + 1);
		} finally {
			close(fis);
		}

	}

	public static void byteToFile(File fic, byte[] b) throws IOException {
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(fic);
			fos.write(b);
		} finally {
			close(fos);
		}
	}

	public static void byteToGzFile(File fic, byte[] b) throws IOException {
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(fic);
			fos.write(compressGZipByte(b));
		} finally {
			close(fos);
		}
	}

	/**
	 * Permet d'extraire les donnees d'un InputDtream vers un tableau de byte[]
	 * 
	 * @param is
	 * @param taillePrevisionnelle
	 * @return
	 * @throws IOException
	 */
	public static byte[] inputStreamToByte(InputStream is,
			int taillePrevisionnelle) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream(
				taillePrevisionnelle);
		byte[] buffer = new byte[taillePrevisionnelle];
		int nb;
		while ((nb = is.read(buffer)) > 0) {
			bos.write(buffer, 0, nb);
		}
		return bos.toByteArray();
		/*
		 * taillePrevisionnelle=((taillePrevisionnelle==1)?MailRecuOBJ.TAILLE_MOYENNE_MAIL
		 * :taillePrevisionnelle); byte[] retour; ArrayList listeContenu = new
		 * ArrayList(); byte[] byteContenu = new byte[taillePrevisionnelle];
		 * 
		 * // Extraction des donnees de l'inputStream int tailleReelle=0; int
		 * nbOctetDernierSegment=0; int nbOctet; while
		 * ((nbOctet=is.read(byteContenu))>0) { tailleReelle +=nbOctet; if
		 * (nbOctet==taillePrevisionnelle) { listeContenu.add(byteContenu);
		 * byteContenu = new byte[taillePrevisionnelle]; } else {
		 * listeContenu.add(byteContenu); } nbOctetDernierSegment = nbOctet; }
		 * byteContenu = null; if
		 * ((listeContenu.size()==1)&&(taillePrevisionnelle
		 * ==nbOctetDernierSegment)) { retour = (byte[])listeContenu.get(0); }
		 * else { // Creation d'un segment byte unique. retour = new
		 * byte[tailleReelle]; int tailleListe = listeContenu.size(); int
		 * position = 0; byte[] b; for (int i=0;i<tailleListe;i++) { b =
		 * (byte[])listeContenu.get(i); if (i==tailleListe-1) {
		 * System.arraycopy(b,0,retour,position,nbOctetDernierSegment); } else {
		 * System.arraycopy(b,0,retour,position,b.length); } position+=b.length;
		 * listeContenu.set(i,null); b=null; } listeContenu.clear();
		 * listeContenu = null; } return retour;
		 */
	}

	/**
	 * Permet d'extraire les donnees d'un InputDtream vers un tableau de byte[]
	 * 
	 * @param is
	 * @param taillePrevisionnelle
	 * @return
	 * @throws IOException
	 */
	public static byte[] inputStreamToGZipByte(InputStream is,
			int taillePrevisionnelle) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		java.util.zip.GZIPOutputStream gz = new java.util.zip.GZIPOutputStream(
				bos);

		byte[] byteContenu = new byte[taillePrevisionnelle];
		// Extraction des donnees de l'inputStream
		int nbOctet;
		while ((nbOctet = is.read(byteContenu)) > 0) {
			gz.write(byteContenu, 0, nbOctet);
		}
		gz.finish();
		return bos.toByteArray();
	}

	/**
	 * Permet d'extraire les donnees d'un InputDtream vers un tableau de byte[]
	 * 
	 * @param is
	 * @param taillePrevisionnelle
	 * @return
	 * @throws IOException
	 */
	public static byte[] compressGZipByte(byte[] b) throws IOException {
		ByteArrayInputStream bis = new ByteArrayInputStream(b);
		return StreamUtility.inputStreamToGZipByte(bis, bis.available());
	}

	/**
	 * Permet d'extraire les donnees d'un InputDtream vers un tableau de byte[]
	 * 
	 * @param is
	 * @param taillePrevisionnelle
	 * @return
	 * @throws IOException
	 */
	public static byte[] uncompressGZipByte(byte[] b) throws IOException {
		ByteArrayInputStream bis = new ByteArrayInputStream(b);
		java.util.zip.GZIPInputStream gz = new java.util.zip.GZIPInputStream(
				bis, bis.available());
		return StreamUtility.inputStreamToByte(gz, gz.available());
	}

	public static void uncompressGzFile(File in, File out) throws IOException {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		GZIPInputStream gz = null;
		try {
			fis = new FileInputStream(in);
			gz = new GZIPInputStream(fis, 1024);

			fos = new FileOutputStream(out);
			byte[] buffer = new byte[1024];
			int nb;
			while ((nb = gz.read(buffer)) > 0) {
				fos.write(buffer, 0, nb);
			}
		} finally {
			close(gz);
			close(fis);
			close(fos);
		}
	}

	public static byte[] uncompressGzFile(File in) throws IOException {
		FileInputStream fis = null;
		ByteArrayOutputStream bos = null;
		GZIPInputStream gz = null;
		try {
			fis = new FileInputStream(in);
			gz = new GZIPInputStream(fis, 1024);

			byte[] buffer = new byte[1024];
			int nb;
			while ((nb = gz.read(buffer)) > 0) {
				bos.write(buffer, 0, nb);
			}
			return bos.toByteArray();
		} finally {
			close(gz);
			close(fis);
		}
	}

	/**
	 * Permet d'extraire les donnees d'un InputDtream vers un tableau de byte[]
	 * 
	 * @param is
	 * @param taillePrevisionnelle
	 * @return
	 * @throws IOException
	 */
	public static byte[] uncompressBZip2Byte(byte[] b) throws IOException {
		Process p = Runtime.getRuntime().exec("bunzip2");
		OutputStream os = p.getOutputStream();
		os.write(b);
		os.close();
		return StreamUtility.inputStreamToByte(p.getInputStream(), 1024);

	}

	/**
	 * M�thode permettant de convertir les carac�tres DOS en caract�res Windows
	 * 
	 * @param contenu
	 *            byte[] La chaine � convertir
	 * @return boolean true si une modification a �t� faite false sinon � � � �
	 *         � 85 82 97 8A 87 � � � � � E0 E9 F9 E8 E7
	 */
	public static boolean convertOEM2ANSI(byte[] contenu) {
		/**
		 * rappel : - byte, from -128 to 127, inclusive - short, from -32768 to
		 * 32767, inclusive - int, from -2147483648 to 2147483647, inclusive -
		 * long, from -9223372036854775808 to 9223372036854775807, inclusive -
		 * char, from '\u0000' to '\uffff' inclusive, that is, from 0 to 65535
		 */
		boolean retour = false;
		for (int i = 0; i < contenu.length; i++) {
			switch (contenu[i]) {
			case (byte) 0x00: // Logiciel pourri
				contenu[i] = (byte) 0x20;
				retour = true;
				break;
			case (byte) 0x85: // �
				contenu[i] = (byte) 0xE0;
				retour = true;
				break;
			case (byte) 0x82: // �
				contenu[i] = (byte) 0xE9;
				retour = true;
				break;
			case (byte) 0x97: // �
				contenu[i] = (byte) 0xF9; // 249
				retour = true;
				break;
			case (byte) 0x8A: // �
				contenu[i] = (byte) 0xE8;
				retour = true;
				break;
			case (byte) 0x87: // �
				contenu[i] = (byte) 0xE7;
				retour = true;
				break;
			// D�but ajout HSK - 01/06/2004 - Pour substituer les caract�res
			// majuscules accentu�s (hexa en ASCII)
			case (byte) 0xC0: // S�rie des A accentu�s
			case (byte) 0xC1:
			case (byte) 0xC2:
			case (byte) 0xC3:
			case (byte) 0xC4:
			case (byte) 0xC5:
			case (byte) 0xC6:
				contenu[i] = (byte) 0x41;
				retour = true;
				break;
			case (byte) 0xC7: // C avec une c�dille
				contenu[i] = (byte) 0x43;
				retour = true;
				break;
			case (byte) 0xC8: // S�rie des E accentu�s
			case (byte) 0xC9:
			case (byte) 0xCA:
			case (byte) 0xCB:
				contenu[i] = (byte) 0x45;
				retour = true;
				break;
			case (byte) 0xCC: // S�rie des I accentu�s
			case (byte) 0xCD:
			case (byte) 0xCE:
			case (byte) 0xCF:
				contenu[i] = (byte) 0x49;
				retour = true;
				break;
			case (byte) 0xD1: // N avec un tilde
				contenu[i] = (byte) 0x4E;
				retour = true;
				break;
			case (byte) 0xD2: // S�rie des O (�) accentu�s
			case (byte) 0xD3:
			case (byte) 0xD4:
			case (byte) 0xD5:
			case (byte) 0xD6:
				contenu[i] = (byte) 0x4F;
				retour = true;
				break;
			case (byte) 0xD9: // S�rie des U accentu�s
			case (byte) 0xDA:
			case (byte) 0xDB:
			case (byte) 0xDC:
				contenu[i] = (byte) 0x55;
				retour = true;
				break;
			case (byte) 0xDD: // Y avec un trema
				contenu[i] = (byte) 0x59;
				retour = true;
				break;
			// Fin ajout HSK - 01/06/2004 - Pour substituer les caract�res
			// majuscules accentu�s
			}
		}
		return retour;
	}

	public static byte[] supprimer(byte[] contenu, byte[] supp) {
		return supprimer(contenu, new byte[][] { supp });
	}

	public static byte[] supprimer(byte[] contenu, byte[][] supp) {
		int total = 0;
		ArrayList alByte = new ArrayList();
		int prec = 0, index;
		byte[] cont;
		Indice indice;
		int indexMoinsPrec;
		while ((indice = indexOf(contenu, supp, prec, -1)) != null) {
			indexMoinsPrec = indice.getIndex() - prec;
			if (indexMoinsPrec > 0) {
				cont = new byte[indexMoinsPrec];
				System.arraycopy(contenu, prec, cont, 0, indexMoinsPrec);
				alByte.add(cont);
				total += indexMoinsPrec;
				// System.out.println(new String(cont));
			}
			prec = indice.getContinuerALindex();
		}

		byte[] retour;
		if (prec == 0 && indice == null) { // Rien a �t� trouv�
			retour = contenu;
		} else {
			if (prec < contenu.length) {
				cont = new byte[contenu.length - prec];
				System.arraycopy(contenu, prec, cont, 0, contenu.length - prec);
				alByte.add(cont);
				total += contenu.length - prec;
			}
			if (alByte.size() == 1) {
				retour = (byte[]) alByte.get(0);
			} else {
				retour = new byte[total];
				int tailleListe = alByte.size();
				int position = 0;
				for (int i = 0; i < tailleListe; i++) {
					cont = (byte[]) alByte.get(i);
					System.arraycopy(cont, 0, retour, position, cont.length);
					position += cont.length;
					alByte.set(i, null);
				}
			}
		}
		alByte.clear();
		alByte = null;
		return retour;
	}

	public static byte[] remplacer(byte[] contenu, byte[] recherche,
			byte[] remplacement) {
		int total = 0;
		ArrayList alByte = new ArrayList();
		int prec = 0, index;
		byte[] cont;
		int indice;
		int indexMoinsPrec;
		while ((indice = indexOf(contenu, recherche, prec)) != -1) {
			indexMoinsPrec = indice - prec;
			// if (indexMoinsPrec>0){
			cont = new byte[indexMoinsPrec];
			System.arraycopy(contenu, prec, cont, 0, indexMoinsPrec);
			alByte.add(cont);
			total += indexMoinsPrec + remplacement.length;
			// System.out.println(new String(cont));
			// }
			prec = indice + recherche.length;
		}

		byte[] retour;
		if (prec == 0 && indice == -1) { // Rien a �t� trouv�
			retour = contenu;
		} else {
			if (prec < contenu.length) {
				cont = new byte[contenu.length - prec];
				System.arraycopy(contenu, prec, cont, 0, contenu.length - prec);
				alByte.add(cont);
				total += contenu.length - prec;
			} else {
				alByte.add(new byte[0]);
			}
			if (alByte.size() == 1) {
				retour = (byte[]) alByte.get(0);
			} else {
				retour = new byte[total];
				int tailleListe = alByte.size();
				int position = 0;
				for (int i = 0; i < tailleListe; i++) {
					cont = (byte[]) alByte.get(i);
					if (cont.length > 0) {
						System
								.arraycopy(cont, 0, retour, position,
										cont.length);
						position += cont.length;
					}
					if (i < tailleListe - 1) {
						System.arraycopy(remplacement, 0, retour, position,
								remplacement.length);
						position += remplacement.length;
					}
					alByte.set(i, null);
				}
			}
		}
		alByte.clear();
		alByte = null;
		return retour;
	}

	/**
	 * M�thode qui permet de rechercher une chaine de caract�re dans un flux de
	 * byte
	 * 
	 * @param contenu
	 * @param recherche
	 * @param charset
	 *            a utiliser lors de la conversion de 'recherche' en bytes
	 * @return l'index de la premi�re occurence trouv�e.
	 */
	// public static int indexOf(byte[] contenu, String recherche, String
	// charset) {
	// return indexOf(contenu, recherche, charset, 0, -1);
	// }
	//
	// /**
	// * M�thode qui permet de rechercher une chaine de caract�re dans un flux
	// de byte
	// * Utilise le charset ISO_8859_1 par defaut
	// * @param contenu
	// * @param recherche
	// * @return l'index de la premi�re occurence trouv�e.
	// */
	// public static int indexOf(byte[] contenu, String recherche) {
	// return indexOf(contenu, recherche, null, 0, -1);
	// }
	//
	// public static int indexOf(byte[] contenu, String recherche, int debut) {
	// return indexOf(contenu, recherche, null, debut, -1);
	// }

	// /**
	// * M�thode qui permet de rechercher une chaine de caract�re dans un flux
	// de byte
	// * @param contenu
	// * @param recherche
	// * @param charset a utiliser lors de la conversion de 'recherche' en
	// bytes, si null utilise iso_8859_1 par defaut, si non supporte, celui de
	// l'os sera utilise.
	// * @return l'index de la premi�re occurence trouv�e.
	// */
	// public static int indexOf(byte[] contenu, String recherche, String
	// charset, int debut, int fin) {
	// if (charset == null)
	// charset = ConstantsEDI.DEFAULT_CHARSET;
	// byte[] rec = null;
	// try {
	// rec = recherche.getBytes(charset);
	// }
	// catch (UnsupportedEncodingException ex) {
	// rec = recherche.getBytes(); //celui de l'os par defaut
	// }
	// return indexOf(contenu, rec, debut, fin);
	// }

	public static class Indice {
		/** */
		private int index;
		/** chaine trouvee */
		private byte[] chaine;
		private int indexFin;

		public Indice(int index, int indexFin, byte[] chaine) {
			this.index = index;
			this.indexFin = indexFin;
			this.chaine = chaine;
		}

		public int getIndex() {
			return index;
		}

		public byte[] getChaineTrouvee() {
			return chaine;
		}

		public int getContinuerALindex() {
			return indexFin + 1;
		}

		public int getTailleChaine() {
			return indexFin - index + 1;
		}
	}

	/**
	 * Recherche sur plusieurs chaines d'un seul coup. Retourne la position de
	 * la premiere chaine trouv�e.
	 * 
	 * @param contenu
	 * @param rec
	 *            tableau de chaines a chercher
	 * @param debut
	 *            indice de debut
	 * @param fin
	 *            indice de fin (pour limiter la recherche), -1 indique pas de
	 *            limite
	 * @return Indice
	 */
	public static Indice indexOf(byte[] contenu, byte[][] rec, int debut,
			int fin) {
		return indexOf(contenu, rec, false, debut, fin);
	}

	/**
	 * Recherche sur plusieurs chaines d'un seul coup. Retourne la position de
	 * la premiere chaine trouv�e.
	 * 
	 * @param contenu
	 * @param rec
	 *            tableau de chaines a chercher
	 * @param debut
	 *            indice de debut
	 * @param fin
	 *            indice de fin (pour limiter la recherche), -1 indique pas de
	 *            limite
	 * @return Indice
	 */
	public static Indice indexOf(byte[] contenu, byte[][] rec,
			boolean ignoreCR, int debut, int fin) {
		int[] indice = new int[rec.length];
		int[] indiceDeb = new int[rec.length];
		for (int j = 0; j < indice.length; j++) { // Initialisation du tableau
													// indice des chaines
													// recherches
			indiceDeb[j] = -1;
		}
		byte b;
		boolean contient;
		if (debut < 0)
			debut = 0;
		if (debut > contenu.length)
			debut = contenu.length;
		if (fin <= 0 || fin > contenu.length)
			fin = contenu.length;
		boolean tenirCompteCR = !ignoreCR;
		for (int i = debut; i < fin; i++) {
			if (tenirCompteCR || (contenu[i] != '\r' && contenu[i] != '\n')) {
				for (int j = 0; j < indice.length; j++) {
					b = rec[j][indice[j]];
					contient = (b == 0) || (b == contenu[i]);
					if (indice[j] > 0 && !contient) {
						indiceDeb[j] = -1;
						indice[j] = 0;
						b = rec[j][indice[j]];
						contient = (b == 0) || (b == contenu[i]);
					}
					if (contient) {
						if (indiceDeb[j] == -1) {
							indiceDeb[j] = i;
						}
						indice[j]++;
						if (indice[j] == rec[j].length) {
							return new Indice(indiceDeb[j], i, rec[j]);
						}
					}
				}
			}
		}
		return null;

	}

	private static int indexOf(byte[] contenu, byte[] rec, int debut) {
		return indexOf(contenu, rec, debut, -1);
	}

	public static int indexOf(byte[] contenu, byte[] rec, int debut, int fin) {
		return indexOf(contenu, rec, debut, fin, true);
	}

	/**
	 * La methode de base utilis�e par les autres m�thodes
	 * 
	 * @param contenu
	 *            tableau source
	 * @param rec
	 *            tableau a cherche
	 * @param debut
	 *            indice de debut
	 * @param fin
	 *            indice de fin (pour limiter la recherche), -1 indique pas de
	 *            limite
	 * @param zeroAsAny
	 *            si true les caract�re � zero dans la chaine recherch�e peuvent
	 *            correspondrent � n'importe quel caract�re
	 * @return pos de rec dans contenu ou -1 si non trouve.
	 */
	public static int indexOf(byte[] contenu, byte[] rec, int debut, int fin,
			boolean zeroAsAny) {
		byte b;
		int indice = 0;
		if (debut < 0)
			debut = 0;
		if (debut > contenu.length)
			debut = contenu.length;
		if (fin <= 0 || fin > contenu.length)
			fin = contenu.length;
		boolean contient;
		for (int i = debut; i < fin; i++) {
			b = rec[indice];
			contient = (b == 0 && zeroAsAny) || (b == contenu[i]);
			if ((indice > 0) && (!contient)) {
				indice = 0;
				b = rec[indice];
				contient = (b == 0) || (b == contenu[i]);
			}
			if (contient) {
				if (++indice == rec.length) {
					return i - rec.length + 1;
				}
			}
		}
		return -1;
	}

	public static boolean isInterchangeTest(byte[] inter) {
		int indexUng = StreamUtility.indexOf(inter, "+1'UNG+".getBytes(), 0,
				300);
		int indexUnh = StreamUtility.indexOf(inter, "'UNH+".getBytes(), 0, 300);
		return (indexUng != -1 && indexUng < indexUnh) ? true : false;

	}

	/*
	 * private static byte[] replace(byte[] contenu, byte[] rec, byte[] rep) {
	 * byte b; int indice=0; boolean contient; for (int
	 * i=debut;i<contenu.length;i++) { b = rec[indice]; contient =
	 * (b==0)||(b==contenu[i]); if ((indice>0)&&(!contient)) { indice = 0; b =
	 * rec[indice]; contient = (b==0)||(b==contenu[i]); } if (contient) { if
	 * (++indice==rec.length) { return i-rec.length+1; } } } return -1; }
	 */

	/**
	 * M�thode qui permet de rechercher une chaine de caract�re dans un flux de
	 * byte
	 * 
	 * @param contenu
	 * @param recherche
	 * @return l'index de la derni�re occurence trouv�e.
	 */
	public static int lastIndexOf(byte[] contenu, String recherche) {
		byte[] rec = recherche.getBytes();
		byte b;
		int indice = recherche.length() - 1;
		boolean contient;
		for (int i = contenu.length - 1; i >= 0; i--) {
			b = rec[indice];
			contient = (b == 0) || (b == contenu[i]);
			if ((indice < recherche.length() - 1) && (!contient)) {
				indice = recherche.length() - 1;
				b = rec[indice];
				contient = (b == 0) || (b == contenu[i]);
			}

			if (contient) {
				if (indice-- == 0) {
					return i;
				}
			}
		}
		return -1;
	}

	public static int indexOf(InputStream is, String recherche)
			throws IOException {
		BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream(is, 4096);
			byte[] buffer = new byte[4096];
			byte[] rec = recherche.getBytes();
			byte b;
			int indice = 0;
			boolean contient;
			int taille;
			int index = 0;
			while ((taille = bis.read(buffer)) != -1) {
				for (int i = 0; i < taille; i++) {
					b = rec[indice];
					contient = (b == 0) || (b == buffer[i]);
					if ((indice > 0) && (!contient)) {
						indice = 0;
						b = rec[indice];
						contient = (b == 0) || (b == buffer[i]);
					}
					if (contient) {
						if (++indice == rec.length) {
							return (index + i) - rec.length + 1;
						}
					}
				}
				index += taille;
			}
			return -1;

		} finally {
			close(bis);
		}
	}

	// /**
	// * M�thode qui permet de rechercher une chaine de caract�re dans un flux
	// de byte
	// * @param contenu
	// * @param recherche
	// * @return true si une occurence a �t� trouv�e.
	// */
	// public static boolean contains(byte[] contenu, String recherche) {
	// return indexOf(contenu, recherche) != -1;
	// }

	/**
	 * 
	 * @param is
	 * @param os
	 * @throws IOException
	 */
	public static void copy(InputStream is, OutputStream os, byte[] buffer)
			throws IOException {
		int nb;
		while ((nb = is.read(buffer)) > 0) {
			os.write(buffer, 0, nb);
		}
	}

	/**
	 * 
	 * @param is
	 * @param os
	 * @throws IOException
	 */
	public static void copy(InputStream is, OutputStream os) throws IOException {
		copy(is, os, new byte[1024]);
	}

	/**
	 * 
	 * @param is
	 * @param os
	 * @throws IOException
	 */
	public static void copy(InputStream is, OutputStream[] os)
			throws IOException {
		byte[] buffer = new byte[32768];
		int nb;
		while ((nb = is.read(buffer)) > 0) {
			for (int i = 0; i < os.length; i++) {
				os[i].write(buffer, 0, nb);
			}
		}
		// copy(is, os, new byte[10240]);
	}

	public static void close(InputStream is) {
		if (is != null) {
			try {
				is.close();
			} catch (IOException ignore) {
			}
		}
	}

	public static void close(OutputStream os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException ignore) {
			}
		}
	}

	public static void close(Channel fc) {
		if (fc != null) {
			try {
				fc.close();
			} catch (IOException ignore) {
			}
		}
	}

	public static void close(Reader os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException ignore) {
			}
		}
	}

	// public static void close(LigneWriter os) {
	// if (os != null) {
	// os.close();
	// }
	// }
	//
	// public static void close(LigneReader os) {
	// if (os != null) {
	// os.close();
	// }
	// }

	public static void close(Writer os) {
		if (os != null) {
			try {
				os.close();
			} catch (IOException ignore) {
			}
		}
	}

	// public static void main(String[] args) {
	// try {
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("AAAAAA".getBytes()), 3)));
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("".getBytes()), 3)));
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("A".getBytes()), 3)));
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("AA".getBytes()), 3)));
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("AAA".getBytes()), 3)));
	// // System.out.println(new String(inputStreamToByte(new
	// ByteArrayInputStream("AAAA".getBytes()), 3)));
	// File rep = new File("/VAR/CRTDUCS2");
	// File[] ficzs = rep.listFiles(new NotDirectoryFilter());
	// for (int i = 0; i < ficzs.length; i++) {
	// File gz = new File("/VAR/CRTDUCS2/testGz", ficzs[i].getName());
	// System.out.println(ficzs[i].getName() + " " + i);
	// FileOutputStream fos = new FileOutputStream(gz);
	// fos.write(fileToGzByte(ficzs[i]));
	// fos.close();
	// uncompressGzFile(gz, new File("/VAR/CRTDUCS2/test", ficzs[i].getName()));
	// }
	// System.exit(0);
	// }
	// catch (IOException ex2) {
	// ex2.printStackTrace();
	// }
	//
	// Indice i = indexOf("UNA+:;   UNA+:;\n\r'".getBytes(), new byte[][]
	// {"UNA+:;'".getBytes()}, true, -1, -1);
	// System.out.println(i == null ? -1 : i.getIndex());
	// System.out.println(i == null ? -1 : i.getTailleChaine());
	// System.out.println(i == null ? -1 : i.getContinuerALindex());
	// //System.exit(0);
	// System.out.println(new String(remplacer("CABCCDEFCC".getBytes(),
	// "C".getBytes(), "-C-".getBytes())));
	// byte[] rech1 =
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA".getBytes();
	// System.out.println("0 " + indexOf(rech1, "A"));
	// System.out.println("51 " + lastIndexOf(rech1, "A"));
	// System.out.println("0 " + lastIndexOf(rech1, "AB"));
	// System.out.println("50 " + lastIndexOf(rech1, "BA"));
	// System.out.println("0 " + indexOf(rech1, "AB"));
	// System.out.println("-1 " + indexOf(rech1, "AAB"));
	// System.out.println("26 " + indexOf(rech1, "ZY"));
	// System.out.println("25 " + indexOf(rech1, "ZZY"));
	// System.out.println("-1 " + indexOf(rech1, "ZZYY"));
	// System.out.println("-1 " + indexOf(rech1, "BAC"));
	// System.out.println("-1 " + lastIndexOf(rech1, "DABC"));
	// System.out.println("0 " + indexOf(rech1,
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA"));
	// System.out.println("-1 " + indexOf(rech1,
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA0"));
	// System.out.println("0 " + lastIndexOf(rech1,
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA"));
	// System.out.println("-1 " + lastIndexOf(rech1,
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA0"));
	// System.out.println("-1 " + lastIndexOf(rech1, "AB9AB"));
	// System.out.println(new String(supprimer("TOTOLITOTO".getBytes(), new
	// byte[][] {"J".getBytes()})));
	// System.out.println(new String(supprimer("".getBytes(), new byte[][]
	// {"J".getBytes()})));
	// System.out.println(new String(supprimer("J".getBytes(), new byte[][]
	// {"J".getBytes()})));
	// System.out.println(new String(supprimer("BONJ".getBytes(), new byte[][]
	// {"J".getBytes()})));
	// System.out.println(new String(supprimer("JOUR".getBytes(), new byte[][]
	// {"J".getBytes()})));
	// System.out.println(new String(supprimer("BONJOUR".getBytes(), new
	// byte[][] {"J".getBytes()})));
	// System.out.println(new String(supprimer("BONJOUR LE JOUR".getBytes(), new
	// byte[][] {"J".getBytes()})));
	// System.out.println(new String(supprimer("BONJOUR LE JOURJ".getBytes(),
	// new byte[][] {"J".getBytes()})));
	// System.out.println(new String(supprimer("JBONJOUR LE JOURJ".getBytes(),
	// new byte[][] {"J".getBytes()})));
	// System.out.println(new String(supprimer("JBONJOUR LE JOURJ".getBytes(),
	// new byte[][] {"JB".getBytes()})));
	//
	// try {
	// System.out.println("0 " + indexOf(new ByteArrayInputStream(rech1), "A"));
	// System.out.println("0 " + indexOf(new ByteArrayInputStream(rech1),
	// "AB"));
	// System.out.println("-1 " + indexOf(new ByteArrayInputStream(rech1),
	// "AAB"));
	// System.out.println("26 " + indexOf(new ByteArrayInputStream(rech1),
	// "ZY"));
	// System.out.println("25 " + indexOf(new ByteArrayInputStream(rech1),
	// "ZZY"));
	// System.out.println("-1 " + indexOf(new ByteArrayInputStream(rech1),
	// "ZZYY"));
	// System.out.println("-1 " + indexOf(new ByteArrayInputStream(rech1),
	// "BAC"));
	// System.out.println("0 " +
	// indexOf(new ByteArrayInputStream(rech1),
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA"));
	// System.out.println("-1 " +
	// indexOf(new ByteArrayInputStream(rech1),
	// "ABCDEFGHIJKLMNOPQRSTUVWXYZZYXWVUTSRQPONMLKJIHGFEDCBA0"));
	// byte[] cont = "���������������������������".getBytes();
	// convertOEM2ANSI(cont);
	// System.out.println(new String(cont));
	// System.out.println("AAAAAAACEEEEIIIINOOOOOUUUUY");
	//
	// }
	// catch (IOException ex) {
	// ex.printStackTrace();
	// }
	//
	// FileInputStream fic = null;
	// try {
	// fic = new FileInputStream("C:/VAR/TIN/TVA/816-MOISAN Stiphane");
	// byte[] cont = inputStreamToByte(fic, fic.available());
	// System.out.println(lastIndexOf(cont, "'BGM+"));
	// System.out.println(indexOf(cont, "'BGM+"));
	// }
	// catch (IOException ex) {
	// ex.printStackTrace();
	// }
	// finally {
	// try {
	// if (fic != null)
	// fic.close();
	// }
	// catch (IOException ex1) {
	// }
	// }
	//
	// }

	/**************************************************************************
	 * Converti l'objet MorceauInterchange en un fichier
	 * 
	 * @param fichier
	 *            File
	 * @param morceau
	 *            MorceauInterchange
	 * @throws RunnerException
	 *************************************************************************/
	// public static void morceauToFile(File fichier, MorceauInterchange
	// morceau) throws IOException {
	// FileOutputStream fos = null;
	// try {
	// fos = new FileOutputStream(fichier);
	// morceau.writeTo(fos);
	// }
	// finally {
	// close(fos);
	// }
	//
	// }

}

/**
 * unicode 0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; 0042;LATIN CAPITAL
 * LETTER B;Lu;0;L;;;;;N;;;;0062; 0043;LATIN CAPITAL LETTER
 * C;Lu;0;L;;;;;N;;;;0063; 0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;
 * 0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; 0046;LATIN CAPITAL LETTER
 * F;Lu;0;L;;;;;N;;;;0066; 0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;
 * 0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; 0049;LATIN CAPITAL LETTER
 * I;Lu;0;L;;;;;N;;;;0069; 004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;
 * 004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; 004C;LATIN CAPITAL LETTER
 * L;Lu;0;L;;;;;N;;;;006C; 004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;
 * 004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; 004F;LATIN CAPITAL LETTER
 * O;Lu;0;L;;;;;N;;;;006F; 0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;
 * 0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; 0052;LATIN CAPITAL LETTER
 * R;Lu;0;L;;;;;N;;;;0072; 0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;
 * 0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; 0055;LATIN CAPITAL LETTER
 * U;Lu;0;L;;;;;N;;;;0075; 0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;
 * 0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; 0058;LATIN CAPITAL LETTER
 * X;Lu;0;L;;;;;N;;;;0078; 0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;
 * 005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; 005B;LEFT SQUARE
 * BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; 005C;REVERSE
 * SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; 005D;RIGHT SQUARE
 * BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; 005E;CIRCUMFLEX
 * ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; 005F;LOW
 * LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; 0060;GRAVE
 * ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; 0061;LATIN SMALL LETTER
 * A;Ll;0;L;;;;;N;;;0041;;0041 0062;LATIN SMALL LETTER
 * B;Ll;0;L;;;;;N;;;0042;;0042 0063;LATIN SMALL LETTER
 * C;Ll;0;L;;;;;N;;;0043;;0043 0064;LATIN SMALL LETTER
 * D;Ll;0;L;;;;;N;;;0044;;0044 0065;LATIN SMALL LETTER
 * E;Ll;0;L;;;;;N;;;0045;;0045 0066;LATIN SMALL LETTER
 * F;Ll;0;L;;;;;N;;;0046;;0046 0067;LATIN SMALL LETTER
 * G;Ll;0;L;;;;;N;;;0047;;0047 0068;LATIN SMALL LETTER
 * H;Ll;0;L;;;;;N;;;0048;;0048 0069;LATIN SMALL LETTER
 * I;Ll;0;L;;;;;N;;;0049;;0049 006A;LATIN SMALL LETTER
 * J;Ll;0;L;;;;;N;;;004A;;004A 006B;LATIN SMALL LETTER
 * K;Ll;0;L;;;;;N;;;004B;;004B 006C;LATIN SMALL LETTER
 * L;Ll;0;L;;;;;N;;;004C;;004C 006D;LATIN SMALL LETTER
 * M;Ll;0;L;;;;;N;;;004D;;004D 006E;LATIN SMALL LETTER
 * N;Ll;0;L;;;;;N;;;004E;;004E 006F;LATIN SMALL LETTER
 * O;Ll;0;L;;;;;N;;;004F;;004F 0070;LATIN SMALL LETTER
 * P;Ll;0;L;;;;;N;;;0050;;0050 0071;LATIN SMALL LETTER
 * Q;Ll;0;L;;;;;N;;;0051;;0051 0072;LATIN SMALL LETTER
 * R;Ll;0;L;;;;;N;;;0052;;0052 0073;LATIN SMALL LETTER
 * S;Ll;0;L;;;;;N;;;0053;;0053 0074;LATIN SMALL LETTER
 * T;Ll;0;L;;;;;N;;;0054;;0054 0075;LATIN SMALL LETTER
 * U;Ll;0;L;;;;;N;;;0055;;0055 0076;LATIN SMALL LETTER
 * V;Ll;0;L;;;;;N;;;0056;;0056 0077;LATIN SMALL LETTER
 * W;Ll;0;L;;;;;N;;;0057;;0057 0078;LATIN SMALL LETTER
 * X;Ll;0;L;;;;;N;;;0058;;0058 0079;LATIN SMALL LETTER
 * Y;Ll;0;L;;;;;N;;;0059;;0059 007A;LATIN SMALL LETTER
 * Z;Ll;0;L;;;;;N;;;005A;;005A
 * 
 * 
 * 
 * 
 * 00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL
 * LETTER A GRAVE;;;00E0; 00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041
 * 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; 00C2;LATIN CAPITAL LETTER A
 * WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A
 * CIRCUMFLEX;;;00E2; 00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041
 * 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; 00C4;LATIN CAPITAL LETTER A
 * WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;
 * 00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN
 * CAPITAL LETTER A RING;;;00E5; 00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN
 * CAPITAL LETTER A E;ash *;;00E6; 00C7;LATIN CAPITAL LETTER C WITH
 * CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;
 * 00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL
 * LETTER E GRAVE;;;00E8; 00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045
 * 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; 00CA;LATIN CAPITAL LETTER E
 * WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E
 * CIRCUMFLEX;;;00EA; 00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045
 * 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; 00CC;LATIN CAPITAL LETTER
 * I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;
 * 00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL
 * LETTER I ACUTE;;;00ED; 00CE;LATIN CAPITAL LETTER I WITH
 * CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;
 * 00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN
 * CAPITAL LETTER I DIAERESIS;;;00EF; 00D0;LATIN CAPITAL LETTER
 * ETH;Lu;0;L;;;;;N;;Icelandic;;00F0; 00D1;LATIN CAPITAL LETTER N WITH
 * TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; 00D2;LATIN
 * CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O
 * GRAVE;;;00F2; 00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F
 * 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; 00D4;LATIN CAPITAL LETTER O
 * WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O
 * CIRCUMFLEX;;;00F4; 00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F
 * 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; 00D6;LATIN CAPITAL LETTER O
 * WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;
 * 00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; 00D8;LATIN CAPITAL LETTER O WITH
 * STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; 00D9;LATIN CAPITAL
 * LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U
 * GRAVE;;;00F9; 00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055
 * 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; 00DB;LATIN CAPITAL LETTER U
 * WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U
 * CIRCUMFLEX;;;00FB; 00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055
 * 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; 00DD;LATIN CAPITAL LETTER
 * Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;
 * 00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE; 00DF;LATIN
 * SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;; 00E0;LATIN SMALL LETTER A WITH
 * GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 00E1;LATIN
 * SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A
 * ACUTE;;00C1;;00C1 00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061
 * 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 00E3;LATIN SMALL LETTER
 * A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3
 * 00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL
 * LETTER A DIAERESIS;;00C4;;00C4 00E5;LATIN SMALL LETTER A WITH RING
 * ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 00E6;LATIN
 * SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6
 * 00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL
 * LETTER C CEDILLA;;00C7;;00C7 00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065
 * 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 00E9;LATIN SMALL LETTER E
 * WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9
 * 00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL
 * LETTER E CIRCUMFLEX;;00CA;;00CA 00EB;LATIN SMALL LETTER E WITH
 * DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB
 * 00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER
 * I GRAVE;;00CC;;00CC 00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069
 * 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD 00EE;LATIN SMALL LETTER I
 * WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I
 * CIRCUMFLEX;;00CE;;00CE 00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069
 * 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF 00F0;LATIN SMALL LETTER
 * ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0 00F1;LATIN SMALL LETTER N WITH
 * TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 00F2;LATIN
 * SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O
 * GRAVE;;00D2;;00D2 00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F
 * 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 00F4;LATIN SMALL LETTER O
 * WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O
 * CIRCUMFLEX;;00D4;;00D4 00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F
 * 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 00F6;LATIN SMALL LETTER O
 * WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O
 * DIAERESIS;;00D6;;00D6 00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; 00F8;LATIN SMALL
 * LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8
 * 00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER
 * U GRAVE;;00D9;;00D9 00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075
 * 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA 00FB;LATIN SMALL LETTER U
 * WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U
 * CIRCUMFLEX;;00DB;;00DB 00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075
 * 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC 00FD;LATIN SMALL LETTER
 * Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD
 */

